﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace O1.Data.Traversal.Expressions
{
    internal class ExpressionParser
    {
        //// BIG TODO: Analyze these operators and figure out how to represent them.
        ////TSource Aggregate<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, TSource, TSource>> func);
        ////TAccumulate Aggregate<TSource, TAccumulate>(this IQueryable<TSource> source, TAccumulate seed, Expression<Func<TAccumulate, TSource, TAccumulate>> func);
        ////TResult Aggregate<TSource, TAccumulate, TResult>(this IQueryable<TSource> source, TAccumulate seed, Expression<Func<TAccumulate, TSource, TAccumulate>> func, Expression<Func<TAccumulate, TResult>> selector);

        ////bool All<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);

        ////bool Any<TSource>(this IQueryable<TSource> source);
        ////bool Any<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);

        ////decimal? Average(this IQueryable<decimal?> source);
        ////decimal Average(this IQueryable<decimal> source);
        ////double? Average(this IQueryable<double?> source);
        ////double Average(this IQueryable<double> source);
        ////float? Average(this IQueryable<float?> source);
        ////float Average(this IQueryable<float> source);
        ////double? Average(this IQueryable<int?> source);
        ////double Average(this IQueryable<int> source);
        ////double? Average(this IQueryable<long?> source);
        ////double Average(this IQueryable<long> source);
        ////decimal? Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, decimal?>> selector);
        ////decimal Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, decimal>> selector);
        ////double? Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, double?>> selector);
        ////double Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, double>> selector);
        ////float? Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, float?>> selector);
        ////float Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, float>> selector);
        ////double? Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int?>> selector);
        ////double Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int>> selector);
        ////double? Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, long?>> selector);
        ////double Average<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, long>> selector);

        ////bool Contains<TSource>(this IQueryable<TSource> source, TSource item);
        ////bool Contains<TSource>(this IQueryable<TSource> source, TSource item, IEqualityComparer<TSource> comparer);

        ////int Count<TSource>(this IQueryable<TSource> source);
        ////int Count<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);

        ////IQueryable<TSource> Distinct<TSource>(this IQueryable<TSource> source);
        ////IQueryable<TSource> Distinct<TSource>(this IQueryable<TSource> source, IEqualityComparer<TSource> comparer);

        ////TSource ElementAt<TSource>(this IQueryable<TSource> source, int index);
        ////TSource ElementAtOrDefault<TSource>(this IQueryable<TSource> source, int index);

        ////IQueryable<TSource> Except<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2);
        ////IQueryable<TSource> Except<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2, IEqualityComparer<TSource> comparer);

        ////TSource First<TSource>(this IQueryable<TSource> source);
        ////TSource First<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
        ////TSource FirstOrDefault<TSource>(this IQueryable<TSource> source);
        ////TSource FirstOrDefault<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);

        ////IQueryable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
        ////IQueryable<TResult> GroupBy<TSource, TKey, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TKey, IEnumerable<TSource>, TResult>> resultSelector);
        ////IQueryable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector);
        ////IQueryable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IEqualityComparer<TKey> comparer);
        ////IQueryable<TResult> GroupBy<TSource, TKey, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TKey, IEnumerable<TSource>, TResult>> resultSelector, IEqualityComparer<TKey> comparer);
        ////IQueryable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector, Expression<Func<TKey, IEnumerable<TElement>, TResult>> resultSelector);
        ////IQueryable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector, IEqualityComparer<TKey> comparer);
        ////IQueryable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector, Expression<Func<TKey, IEnumerable<TElement>, TResult>> resultSelector, IEqualityComparer<TKey> comparer);

        ////IQueryable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IQueryable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, IEnumerable<TInner>, TResult>> resultSelector);
        ////IQueryable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IQueryable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, IEnumerable<TInner>, TResult>> resultSelector, IEqualityComparer<TKey> comparer);

        ////IQueryable<TSource> Intersect<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2);
        ////IQueryable<TSource> Intersect<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2, IEqualityComparer<TSource> comparer);

        ////IQueryable<TResult> Join<TOuter, TInner, TKey, TResult>(this IQueryable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, TInner, TResult>> resultSelector);
        ////IQueryable<TResult> Join<TOuter, TInner, TKey, TResult>(this IQueryable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, TInner, TResult>> resultSelector, IEqualityComparer<TKey> comparer);

        ////TSource Last<TSource>(this IQueryable<TSource> source);
        ////TSource Last<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
        ////TSource LastOrDefault<TSource>(this IQueryable<TSource> source);
        ////TSource LastOrDefault<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);

        ////long LongCount<TSource>(this IQueryable<TSource> source);
        ////long LongCount<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);

        ////TSource Max<TSource>(this IQueryable<TSource> source);
        ////TResult Max<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector);
        ////TSource Min<TSource>(this IQueryable<TSource> source);
        ////TResult Min<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector);

        ////IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
        ////IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer);
        ////IOrderedQueryable<TSource> OrderByDescending<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
        ////IOrderedQueryable<TSource> OrderByDescending<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer);

        ////IQueryable<TSource> Reverse<TSource>(this IQueryable<TSource> source);

        ////IQueryable<TResult> Select<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, int, TResult>> selector);
        ////IQueryable<TResult> Select<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector);
        ////IQueryable<TResult> SelectMany<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, IEnumerable<TResult>>> selector);
        ////IQueryable<TResult> SelectMany<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, int, IEnumerable<TResult>>> selector);
        ////IQueryable<TResult> SelectMany<TSource, TCollection, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, IEnumerable<TCollection>>> collectionSelector, Expression<Func<TSource, TCollection, TResult>> resultSelector);
        ////IQueryable<TResult> SelectMany<TSource, TCollection, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, int, IEnumerable<TCollection>>> collectionSelector, Expression<Func<TSource, TCollection, TResult>> resultSelector);

        ////bool SequenceEqual<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2);
        ////bool SequenceEqual<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2, IEqualityComparer<TSource> comparer);

        ////TSource Single<TSource>(this IQueryable<TSource> source);
        ////TSource Single<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
        ////TSource SingleOrDefault<TSource>(this IQueryable<TSource> source);
        ////TSource SingleOrDefault<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);

        ////IQueryable<TSource> Skip<TSource>(this IQueryable<TSource> source, int count);
        ////IQueryable<TSource> SkipWhile<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
        ////IQueryable<TSource> SkipWhile<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int, bool>> predicate);

        ////decimal? Sum(this IQueryable<decimal?> source);
        ////decimal Sum(this IQueryable<decimal> source);
        ////double? Sum(this IQueryable<double?> source);
        ////double Sum(this IQueryable<double> source);
        ////float? Sum(this IQueryable<float?> source);
        ////float Sum(this IQueryable<float> source);
        ////int? Sum(this IQueryable<int?> source);
        ////int Sum(this IQueryable<int> source);
        ////long? Sum(this IQueryable<long?> source);
        ////long Sum(this IQueryable<long> source);
        ////decimal? Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, decimal?>> selector);
        ////decimal Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, decimal>> selector);
        ////double? Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, double?>> selector);
        ////double Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, double>> selector);
        ////float? Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, float?>> selector);
        ////float Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, float>> selector);
        ////int? Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int?>> selector);
        ////int Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int>> selector);
        ////long? Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, long?>> selector);
        ////long Sum<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, long>> selector);

        ////IQueryable<TSource> Take<TSource>(this IQueryable<TSource> source, int count);
        ////IQueryable<TSource> TakeWhile<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
        ////IQueryable<TSource> TakeWhile<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int, bool>> predicate);

        ////IOrderedQueryable<TSource> ThenBy<TSource, TKey>(this IOrderedQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
        ////IOrderedQueryable<TSource> ThenBy<TSource, TKey>(this IOrderedQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer);
        ////IOrderedQueryable<TSource> ThenByDescending<TSource, TKey>(this IOrderedQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
        ////IOrderedQueryable<TSource> ThenByDescending<TSource, TKey>(this IOrderedQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer);

        ////IQueryable<TSource> Union<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2);
        ////IQueryable<TSource> Union<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2, IEqualityComparer<TSource> comparer);

        ////IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
        ////IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int, bool>> predicate);

        ////IQueryable<TResult> Zip<TFirst, TSecond, TResult>(this IQueryable<TFirst> source1, IEnumerable<TSecond> source2, Expression<Func<TFirst, TSecond, TResult>> resultSelector);
    }
}
